#+TITLE: Emacs Configuration
#+DESCRIPTION: Literate emacs config, to be invoked with org-babel-load-file in emacs.d to tangle and apply upon startup
#+PROPERTY: header-args :tangle ~/.config/emacs/emacs_config.el

* Installation info

Make sure to add the below to your ​~~/.emacs~ file (or equivalent) - then tangle this file. It will be stored in .config for XDG compliance.
#+BEGIN_SRC emacs-lisp :tangle no
(load-file "~/.config/emacs/emacs_config.el")
#+END_SRC


* Package Repos
** MELPA package repo
Add the MELPA package repo into the sources for emacs
Do this early in the config to make sure everything that follows can be loaded

#+BEGIN_SRC emacs-lisp
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
(package-initialize)
#+END_SRC


* Keybinds
** Resizing windows
Use Shift+Ctrl with direction keys to resize windows

#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "S-C-<left>") 'shrink-window-horizontally)
(global-set-key (kbd "S-C-<right>") 'enlarge-window-horizontally)
(global-set-key (kbd "S-C-<down>") 'shrink-window)
(global-set-key (kbd "S-C-<up>") 'enlarge-window)
#+END_SRC

** Auto-completion
Use M-TAB to apply smart autocompletion

#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "M-TAB") 'pcomplete)
#+END_SRC

** Disable C-z suspend-frame

Prevent C-z from suspending frame, very annoying habit.

#+BEGIN_SRC emacs-lisp
(put 'suspend-frame 'disabled t)
#+END_SRC


* Start use-package
use-package helps setup variables for other packages... 

#+BEGIN_SRC emacs-lisp
(require 'use-package)
#+END_SRC


* File Management
** Reload file changes
Automatically reload any buffers that have changed on disk, as long as
there are no unsaved changes. This is useful for keeping org-files
synced via syncthing, so my Agenda should always match across devices.

#+BEGIN_SRC emacs-lisp
(global-auto-revert-mode t)
#+END_SRC

** TRAMP remote file editing
"Transparent Remote Access, Multiple Protocols" is for editing files
on remote machines, to avoid dropping to a terminal/ssh/nano to make
any changes to files.

#+BEGIN_SRC emacs-lisp
(use-package tramp
  :ensure t
  :init
  (setq tramp-default-method "ssh"))
#+END_SRC


* Display options
** Line numbers
Display line numbers in all modes by default

#+BEGIN_SRC emacs-lisp
(global-linum-mode t)
#+END_SRC

** Word wrap
Use the word-wrap variable as opposed to visual-line-mode. Pros are:-
+ C-x k kills the whole line, not just the visible part
+ A wrap indicator is shown on the ends
+ And really, I just prefer it

#+BEGIN_SRC emacs-lisp
(setq-default word-wrap t)
(setq truncate-lines nil)
#+END_SRC

*** Org-Mode Wrapping
Despite my best efforts, this has to happen later in the config so it
can be found at the below link, directly after an ~org-reload~ command

[[*Text
 Wrapping][Text Wrapping]]

** which-key shortcut cheat-sheet
Display helper buffer for available keybinds in each mode. For
example, input C-x then wiat a few seconds, a list of legitimate keys
to follow will be displayed.

Does not help with M-x, but tab-completion is your friend there :)

#+BEGIN_SRC emacs-lisp
(use-package which-key
  :ensure t
  :init
  (which-key-mode)
  (which-key-setup-side-window-right-bottom))
#+END_SRC

** Disable menu bar
Hide the menu bar by default

#+BEGIN_SRC emacs-lisp
(menu-bar-mode -1)
#+END_SRC

** Disable cursor blink
Cursor blinking is prevented, so just a solid block is displayed for
my sanity.

#+BEGIN_SRC emacs-lisp
(blink-cursor-mode -1)
#+END_SRC

* Helm Auto-Completion
Use package helm to add improved fuzzy completion to file search, M-x
function, buffer list and more

#+BEGIN_SRC emacs-lisp
(use-package helm
  :ensure t
  :init
  (helm-mode 1)
  :bind
  (("M-x"     . helm-M-x)
   ("C-x C-f" . helm-find-files)
   ("C-x C-b" . helm-buffers-list)
   :map helm-map
   ("TAB"     . helm-execute-persistent-action)
   ("<tab>"   . helm-execute-persistent-action)
   ("C-z"     . helm-select-action)))
  #+END_SRC

Also a few rebindings on helm map, to make tab key work as expected when making helm selections.
C-z brings up the helm actions menu that was previously on tab.


* Development Options

** Python

*** elpy
Enable the elpy environment

#+BEGIN_SRC emacs-lisp
(use-package elpy
  :ensure t
  :init
  (elpy-enable)
  (setq elpy-rpc-virtualenv-path 'current)
  (setq elpy-rpc-python-command "python3"))
#+END_SRC

*** live-py-mode
Enable the option for python live programming

#+BEGIN_SRC emacs-lisp
(use-package live-py-mode
  :ensure t
  :init
  (add-hook 'live-py-mode-hook '(live-py-set-version))
#+END_SRC


** Org-Mode

*** org-babel supported languages
Ensure org-babel can evaluate source blocks in the languages I use

#+BEGIN_SRC emacs-lisp
(org-babel-do-load-languages
  'org-babel-load-languages
  '((emacs-lisp . t)
    (shell . t)
    (python . t)))
#+END_SRC

*** Preserve indentation
Let org-src editor preserve my personal indentations when using the C-c ' source block editor

#+BEGIN_SRC emacs-lisp
(setq org-src-preserve-indentation t)
#+END_SRC


** Highlight Parentheses
Use the package highlight-parentheses to make depth within brackets clearer, with custom colourings for 6 layers of depth.
Hook added for lisp & emacs-lisp modes

#+BEGIN_SRC emacs-lisp
(use-package highlight-parentheses
  :ensure t
  :init
  (setq highlight-parentheses-colors '("white" "black" "black" "black" "black" "black"))
  (setq highlight-parentheses-background-colors '("red" "orange" "yellow" "green" "cyan" "magenta"))
  (add-hook 'emacs-lisp-mode-hook #'highlight-parentheses-mode)
  (add-hook 'lisp-mode-hook #'highlight-parentheses-mode)))
#+END_SRC

#+RESULTS:


* Applications
** elfeed RSS reader
*** Basic package
Settings for the main RSS reader package

~elfeed-db-directory~ is set to store the database in my org file directory, so it will syn with syncthing to my other devices

#+BEGIN_SRC emacs-lisp
(use-package elfeed
  :ensure t
  :config
  (setq elfeed-sort-order 'ascending)
  (setq elfeed-db-directory "~/.elfeed")
  (elfeed-update))
#+END_SRC

*** elfeed-org 
Package to load RSS feeds from an org-file - in my case, "~/org/RSSFeeds.org"
Multiple org-files can be added to the list, to segregate feeds better.

#+BEGIN_SRC emacs-lisp
(use-package elfeed-org
  :ensure t
  :config
  (elfeed-org)
  (setq rmh-elfeed-org-files (list "~/org/RSSFeeds.org")))
#+END_SRC

** ERC

ERC is the built-in IRC chat client. This sets up my default username and server info (using =libera.chat=).[[id:638ff88f-184d-4fd9-9754-ceacd0816fd6][org markdown]]

#+BEGIN_SRC emacs-lisp
(use-package erc
  :ensure t
  :config
  (setq erc-nick "Category")
  (setq erc-nick-uniquifier "^")
  (setq erc-server "irc.libera.chat")
  (setq erc-port "6667"))
#+END_SRC


* Org-Mode Settings
** Keybinds

Basic settings/keybinds for org-mode details

#+BEGIN_SRC emacs-lisp
(require 'org)
(define-key global-map "\C-cl" 'org-store-link)   ;; Copy a link to the current heading
(define-key global-map "\C-ca" 'org-agenda)   ;; Open sub-menu for agenda
(setq org-log-done t)   ;; Show when todo items are closed
#+END_SRC

** Hide formatting marks
Don't display the symbols surround italics/bold/etc text

#+BEGIN_SRC emacs-lisp
(setq org-hide-emphasis-markers t)
#+END_SRC

** Indent headings/hide asterisks
Use org-indent mode to hide the leading stars and auto indent text
Make this the default by hooking org-indent-mode when org-mode begins

#+BEGIN_SRC emacs-lisp
(add-hook 'org-mode-hook 'org-indent-mode)
#+END_SRC

** Agenda settings
Set =~/org/agenda= as folder to auto-scan for the org-mode agenda.
All files in this folder will be automatically added to schedule/TODO list etc.

#+BEGIN_SRC emacs-lisp
(setq org-agenda-files (list "~/org/agenda"))
#+END_SRC

** Reload org after errors
Following errors, running M-X org-reload will force an update/refresh
and normally get the agenda/todo klist funtioning as expected again.

Run this every load to make sure we start error-free

#+BEGIN_SRC emacs-lisp
(org-reload)
#+END_SRC

*** Text Wrapping
Make org startup without truncating lines, for a nice soft
wrap. Trying to run this before the reload seems to get forgotten...

#+BEGIN_SRC emacs-lisp
(setq org-startup-truncated nil)
#+END_SRC

** Org mode code handling

*** Remove confirmation from babel-executions
Skip asking for yes/no confirmation when requesting to evaluate source
blocks in org documents

#+BEGIN_SRC emacs-lisp
(setq org-confirm-babel-evaluate nil)
#+END_SRC


* Org-Roam
Org-Roam is a knowledge-base system based on org-mode syntax

Ensure package is loaded after init and set initial variables

#+BEGIN_SRC emacs-lisp
(defun my/org-roam-list-stubs nil
  "List all org-roam nodes tagged as a stub"
  (interactive)
  (org-roam-node-find nil "#stub"))
  #+END_SRC


#+BEGIN_SRC emacs-lisp
(use-package org-roam
  :ensure t
  :init
  (setq org-roam-v2-ack t)
  ;; Keymap primer
  (define-prefix-command 'org-roam-map)
  (define-key mode-specific-map (kbd "r") 'org-roam-map)
  :custom
  (org-roam-directory (file-truename "~/org/roam"))
  (org-roam-completion-everywhere t)
  (org-roam-graph-max-title-length 30)
  (org-roam-graph-shorten-titles "truncate")
  (org-roam-dailies-capture-templates
   '(("d" "default" plain
      "* %?"
      :if-new (file+head "%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n#+filetags: :journal:"))))
  (org-roam-capture-templates
   '(("d" "Default" plain
      "%?"
      :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n")
      :unnarrowed t)
     ("c" "Ham Contacts" plain
      "Ham Contact\n\n* Details\n\n#+Name: %? \n#+Location: \n#+Station Grid Locator:\n\n* Info\n\n~About the station/operator~\n\n* Contacts\n\n** Timestamp\n~QSO info~"
      :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+filetags: :callsign:ham:")
      :unnarrowed t)
     ("r" "Ham Repeater" plain
      "Repeater\n\n#+Location: %? \n#+Station Grid Locator: \n#+Input Frequency: \n#+Output Frequency: \n#+CTCSS Tone: \n\n"
      :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+filetags: :repeater:ham:")
      :unnarrowed t)
     ("s" "Software" plain
      "Software\n\n#+Name: %?\nWebsite: \nSource Repo: \n\n* Description\n\n\n\n* Usage Information\n\n\n\n* Config Details\n\n"
      :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+filetags: :software:")
      :unnarrowed t)
     ("e" "Emacs Lisp" plain
      "Emacs Lisp Function\n\n#+Function: %?\n\n* Description:-\n\n\n* Example:-\n\n\n* Usage:-\n\n"
      :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+filetags: :emacs:lisp:coding:")
      :unnarrowed t)))
  :bind
  (:map org-roam-map
   ("f" . org-roam-node-find)
   ("g" . org-roam-graph)
   ("i" . org-roam-node-insert)
   ("c" . org-roam-capture)
   ("o" . org-open-at-point)
   ("t" . org-roam-tag-add)
   ("s" . my/org-roam-list-stubs)
   ;; Dailies
   ("j" . org-roam-dailies-capture-today)
   ("l" . org-roam-buffer-toggle))
  :config
  (org-roam-db-autosync-mode)
  (org-roam-setup)
  ;; If using org-roam-protocol
  (require 'org-roam-protocol))
#+END_SRC

** Tag search in org-roam-node-find

This little tweak to the ~org-roam-node-find~ display will also include the file-tags, to help narrow results to certain areas. This was standard behaviour with org-roam v1, and I greatly missed it when upgrading to v2 (even with my very modest collection of nodes).

#+BEGIN_SRC emacs-lisp
(setq org-roam-node-display-template
      (concat "${title:*} "
	      (propertize "${tags:40}" 'face 'org-tag)))
#+END_SRC


* A little bit of fun!

** Chess
Make sure that chess is available, and at a reasonable size to view

#+BEGIN_SRC emacs-lisp
(use-package chess
  :ensure t
  :init
  (setq chess-images-default-size 84))
#+END_SRC

** Wordel
An emacs implementation of "Wordle", for a bit of text based distraction

#+BEGIN_SRC emacs-lisp
(use-package wordel
  :ensure t)
#+END_SRC
